package com.ilop.sthome.common.udp;

import android.content.Context;
import android.util.Log;

import com.ilop.sthome.common.command.SiterCommand;
import com.ilop.sthome.data.bean.GatewayBean;
import com.ilop.sthome.data.greenDao.DeviceInfoBean;
import com.ilop.sthome.utils.greenDao.utils.DeviceDaoUtil;
import com.ilop.sthome.utils.system.NetWorkUtil;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @author skygge
 * @date 2020-03-17.
 * GitHub：javofxu@github.com
 * email：skygge@yeah.net
 * description：搜索内网设备
 */
public class ControllerUdpHelper {
    private static final String TAG = ControllerUdpHelper.class.getSimpleName();
    private static final int PORT = 1025;
    private ExecutorService mSendService;
    private UdpReceiveHelper mUdpReceiveHelper;
    private ExecutorService mReceiveService;

    private Timer mTimer;
    private int mCount = 0;
    boolean mUdpSearchFinish = false;

    private static ControllerUdpHelper instance = null;

    private DatagramSocket mSocket;

    private ControllerUdpHelper(){
        if(mSendService == null){
            mSendService = Executors.newFixedThreadPool(7);
        }
    }

    public static ControllerUdpHelper getInstance(){
        if (instance == null) {
            synchronized (ControllerUdpHelper.class){
                if (instance == null){
                    instance = new ControllerUdpHelper();
                }
            }
        }
        return instance;
    }

    /**
     * 集成UDP连接
     */
    public void onStartConnection(Context context){
        initReceiveUdp(context);
        initSearchUdp(context);
    }

    /**
     * 建立UDP连接
     */
    private void initReceiveUdp(Context context) {
        try {
            String localAddress = NetWorkUtil.getInstance().getLocalIpAddress(context);
            if (localAddress == null) return;
            String subnet = localAddress.substring(0, localAddress.lastIndexOf(".") + 1) + 255;
            InetAddress ip = InetAddress.getByName(localAddress);
            InetAddress inetAddress = InetAddress.getByName(subnet);
            if (mSocket == null){
                mSocket = new DatagramSocket(PORT, ip);
            }
            if (mReceiveService == null){
                mReceiveService = Executors.newSingleThreadExecutor();
            }
            if (mUdpReceiveHelper == null){
                byte[] bytes = new byte[512];
                DatagramPacket mPacket =  new DatagramPacket(bytes, bytes.length, inetAddress, PORT);
                mUdpReceiveHelper = new UdpReceiveHelper(mSocket, mPacket);
                mReceiveService.execute(mUdpReceiveHelper);
            }
        } catch (UnknownHostException | SocketException e) {
            e.printStackTrace();
            cancelReceiveUdp();
        }
    }

    public void registerUdpReceiveCallBack(OnUdpReceiveCallBack callBack) {
        if (mUdpReceiveHelper!=null){
            mUdpReceiveHelper.setCallBack(callBack);
        }
    }

    public void unRegisterUdpReceiveCallBack() {
        onDestroyConnection();
    }

    /**
     * 搜索内网设备
     */
    private void initSearchUdp(Context context){
        mTimer = new Timer();
        try {
            String localAddress = NetWorkUtil.getInstance().getLocalIpAddress(context);
            if (localAddress == null) return;
            String subnet = localAddress.substring(0, localAddress.lastIndexOf(".") + 1) + 255;
            TimerTask mTask = new TimerTask() {
                @Override
                public void run() {
                    mCount++;
                    if (mCount > 3){
                        cancelTimer();
                        activationUdp();
                    }else {
                        sendSearchUdp(subnet);
                    }
                }
            };
            mTimer.schedule(mTask, 0, 1000);
        }catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 发送搜索
     */
    private void sendSearchUdp(String subnet){
        String searchUdp = "{\"action\":\"IOT_KEY?\",\"devID\":\"NULL\"}";
        onSendData(subnet, searchUdp);
    }

    /**
     * 激活udp状态
     */
    private void activationUdp(){
        List<DeviceInfoBean> gatewayList = DeviceDaoUtil.getInstance().findAllGateway();
        if (gatewayList.size()>0) {
            for (DeviceInfoBean gateway : gatewayList) {
                String mDeviceName = gateway.getDeviceName();
                String code = "{\"action\":\"IOT_KEY?\",\"devID\":" + mDeviceName + "}";
                GatewayBean gatewayBean = GatewayUdpUtil.getInstance().checkByName(mDeviceName);
                if (gatewayBean != null) {
                    String ipAddress = gatewayBean.getIpAddress();
                    onSendData(ipAddress, code);
                }
            }
        }
    }

    /**
     * 取消搜索内网设备
     */
    private void cancelTimer() {
        if (mTimer != null) {
            mTimer.cancel();
            mTimer = null;
        }
        mUdpSearchFinish = true;
    }

    /**
     * udp应答
     */
    public void onSendUdpAnswer(String deviceName){
        String ipAddress = GatewayUdpUtil.getInstance().checkByName(deviceName).getIpAddress();
        String code = SiterCommand.appAnswerOk(deviceName, 11);
        onSendData(ipAddress, code);
    }

    /**
     * 发送内网数据
     */
    void onSendData(String ipAddress, String code){
        Runnable runnable = () -> {
            try{
                byte[] bytes = code.getBytes();
                InetAddress address = InetAddress.getByName(ipAddress);
                DatagramPacket dp = new DatagramPacket(bytes, bytes.length, address, PORT);
                Log.i(TAG,"sendCodeUdp " + address + "===" + new String(bytes));
                mSocket.send(dp);
            } catch (IOException | NullPointerException e) {
                Log.e(TAG, "send code error " + e.getLocalizedMessage() );
                onDestroyConnection();
            }
        };
        mSendService.execute(runnable);
    }

    /**
     * 关闭UDP连接
     */
    private void cancelReceiveUdp(){
        if(mUdpReceiveHelper !=null){
            mUdpReceiveHelper.close();
        }
        if(mReceiveService !=null && !mReceiveService.isShutdown()){
            mReceiveService.shutdown();
        }
        GatewayUdpUtil.getInstance().setAllGatewayOffLine();//所有内网设备离线
    }

    /**
     * 关闭通道
     */
    private void onDestroyConnection(){
        if (mSocket != null){
            mSocket.close();
        }
        if(mSendService !=null && !mSendService.isShutdown()){
            mSendService.shutdown();
        }
        cancelReceiveUdp();
        instance = null;
    }
}
